package com.ada.spark.lineage

import org.apache.spark.{SparkConf, SparkContext}

/**
  * RDD只支持粗粒度转换，即在大量记录上执行的单个操作。将创建RDD的一系列Lineage（血统）记录下来，以便恢复丢失的分区。RDD的Lineage会记录RDD的元数据信息和转换行为，当该RDD的部分分区数据丢失时，它可以根据这些信息来重新运算和恢复丢失的数据分区。
  */
object LineageTest {
    def main(args: Array[String]): Unit = {
        //1.初始化配置信息及SparkContext
        val sparkConf: SparkConf = new SparkConf().setAppName("LineageTest").setMaster("local[*]")
        val sc = new SparkContext(sparkConf)

        val wordAndOne = sc.textFile("fruit/fruit.tsv").flatMap(_.split("\t")).map((_, 1))
        val wordAndCount = wordAndOne.reduceByKey(_ + _)
        println(wordAndOne.toDebugString)
        //(2) MapPartitionsRDD[3] at map at LineageTest.scala:11 []
        // |  MapPartitionsRDD[2] at flatMap at LineageTest.scala:11 []
        // |  fruit/fruit.tsv MapPartitionsRDD[1] at textFile at LineageTest.scala:11 []
        // |  fruit/fruit.tsv HadoopRDD[0] at textFile at LineageTest.scala:11 []
        println(wordAndCount.toDebugString)
        //(2) ShuffledRDD[4] at reduceByKey at LineageTest.scala:12 []
        // +-(2) MapPartitionsRDD[3] at map at LineageTest.scala:11 []
        //    |  MapPartitionsRDD[2] at flatMap at LineageTest.scala:11 []
        //    |  fruit/fruit.tsv MapPartitionsRDD[1] at textFile at LineageTest.scala:11 []
        //    |  fruit/fruit.tsv HadoopRDD[0] at textFile at LineageTest.scala:11 []

        println(wordAndOne.dependencies)
        //List(org.apache.spark.OneToOneDependency@79316f3a)
        println(wordAndCount.dependencies)
        //List(org.apache.spark.ShuffleDependency@381d7219)
    }

    /**
      * 窄依赖
      * 窄依赖指的是每一个父RDD的Partition最多被子RDD的一个Partition使用,窄依赖我们形象的比喻为独生子女
      *
      * 宽依赖
      * 宽依赖指的是多个子RDD的Partition会依赖同一个父RDD的Partition，会引起shuffle,总结：宽依赖我们形象的比喻为超生
      *
      * DAG
      * DAG(Directed Acyclic Graph)叫做有向无环图，原始的RDD通过一系列的转换就就形成了DAG，根据RDD之间的依赖关系的不同将DAG划分成不同的Stage，对于窄依赖，partition的转换处理在Stage中完成计算。对于宽依赖，由于有Shuffle的存在，只能在parent RDD处理完成后，才能开始接下来的计算，因此宽依赖是划分Stage的依据。
      */

    /**
      * RDD任务切分中间分为：Application、Job、Stage和Task
      * 1）Application：初始化一个SparkContext即生成一个Application
      * 2）Job：一个Action算子就会生成一个Job
      * 3）Stage：根据RDD之间的依赖关系的不同将Job划分成不同的Stage，遇到一个宽依赖则划分一个Stage。
      */
}
